import java.util.Hashtable;
import java.util.StringTokenizer;


public class Interprete {
	
	Lista opList;
	Lista predicadosList;
	Hashtable<String,Atomo> variablesDelUsuario = new Hashtable<String,Atomo>();
	Hashtable<String,Atomo> funcionesDelUsuario = new Hashtable<String,Atomo>();
	
	
	public Interprete() throws Exception {
		
                opList = new Lista();
		opList.Agregar(new Atomo("car"));
		opList.Agregar(new Atomo("cons"));	
		opList.Agregar(new Atomo("defun"));
		opList.Agregar(new Atomo("+"));
		opList.Agregar(new Atomo("*"));
		
		opList.Agregar(new Atomo("-"));
		opList.Agregar(new Atomo("/"));
		opList.Agregar(new Atomo("cond"));
		opList.Agregar(new Atomo("list"));

		opList.Agregar(new Atomo("="));
		opList.Agregar(new Atomo("/="));
		opList.Agregar(new Atomo("<"));
		opList.Agregar(new Atomo("<="));
		opList.Agregar(new Atomo(">"));
		opList.Agregar(new Atomo(">="));
                
                predicadosList = new Lista();
		predicadosList.Agregar(new Atomo("="));
		predicadosList.Agregar(new Atomo("/="));
		predicadosList.Agregar(new Atomo("<"));
		predicadosList.Agregar(new Atomo("<="));
		predicadosList.Agregar(new Atomo(">"));
		predicadosList.Agregar(new Atomo(">="));
	}

	
	public Atomo analizarIngreso(String expresionAParsear,boolean defineList,boolean reservada)  {
		
		expresionAParsear = expresionAParsear.trim();
		
		
		if (expresionAParsear.compareTo("")==0)
			return new Atomo();
		
		if (!parentesisExactos(expresionAParsear))
                        System.out.println("Los parentesis no estan completamente cerrados o existen parentesis de mas.");
		Atomo atomoDeRespuesta = new Atomo();
		
		
		StringTokenizer separador = new StringTokenizer(expresionAParsear);
		
		String primerToken = separador.nextToken();
		Atomo atomoIngresado = new Atomo(primerToken);

			
		if ((separador.countTokens()==0)){
			
			if ((this.variablesDelUsuario.containsKey(primerToken)) && (!defineList))
				return this.variablesDelUsuario.get(primerToken);
			
			if ((primerToken.compareTo("'()")==0) || ((primerToken.compareTo("()")==0)))
				return new Atomo();

			if (primerToken.charAt(0)=='\''){
				if ((primerToken.charAt(1)!='(') && (primerToken.charAt(primerToken.length()-1)!=')'))
					return new Atomo(primerToken.substring(1));
			}
		}
		
		
		if ((new Atomo(primerToken).comienzaCon("'("))){
			defineList = true;
			atomoDeRespuesta = new Atomo(new Lista());
			atomoDeRespuesta.lista.esOperacion = false;
			
			
			int desdeDondeCortar = expresionAParsear.indexOf('(') + 1;
			int hastaDondeCortar = this.obtenerIndiceDelParentesisQueCierraAlPrimeroEn(expresionAParsear);
			
			
			if ((hastaDondeCortar==expresionAParsear.lastIndexOf(')')) && (!(hastaDondeCortar==expresionAParsear.length()-1)))
                                System.out.println("La expresion tiene datos de mas. Por favor revisar.");
			
			expresionAParsear = expresionAParsear.substring(desdeDondeCortar, hastaDondeCortar);			
		} else if (primerToken.charAt(0)=='('){
			
			int desdeDondeCortar = expresionAParsear.indexOf('(') + 1;
			int hastaDondeCortar = this.obtenerIndiceDelParentesisQueCierraAlPrimeroEn(expresionAParsear);
			
			expresionAParsear = expresionAParsear.substring(desdeDondeCortar,hastaDondeCortar);
			atomoDeRespuesta = new Atomo(new Lista());
			
			
			separador = new StringTokenizer(expresionAParsear);
			
			 	
			
			if (defineList){
				if (!reservada)
					atomoDeRespuesta.lista.esOperacion = false;
				else
					atomoDeRespuesta.lista.esOperacion = true;
			}else {
				atomoDeRespuesta.lista.esOperacion = true;
			}
		}		
		
		
		if (!atomoDeRespuesta.EsLista())
			return new Atomo(expresionAParsear);
		
		separador = new StringTokenizer(expresionAParsear);
		
		while (separador.hasMoreTokens()) {
			Atomo atomoActual = new Atomo(separador.nextToken());

			
			if ((atomoActual.comienzaCon("'(")) || (atomoActual.comienzaCon("("))){
				
				int desdeDondeCortar = expresionAParsear.indexOf(atomoActual.toString());
				expresionAParsear = expresionAParsear.substring(desdeDondeCortar);
				int hastaDondeCortar = this.obtenerIndiceDelParentesisQueCierraAlPrimeroEn(expresionAParsear);
				String expresionDeLaListaInterna = expresionAParsear.substring(0, hastaDondeCortar+1);
				Atomo atomoConLaListaInterna = new Atomo();
				
				boolean esDefun = false;
				boolean esCOND = false;
				
				if (atomoActual.comienzaCon("'("))
					atomoConLaListaInterna = analizarIngreso(expresionDeLaListaInterna, true, reservada);
				else {
					if (atomoDeRespuesta.lista.size() > 0){
						if (atomoDeRespuesta.EsListaConOperacion()){
							String operacionDeLaLista = atomoDeRespuesta.lista.getOp().toString();
							
							
							if ((operacionDeLaLista.compareToIgnoreCase("defun")==0) && (atomoDeRespuesta.lista.size()==2)){
								atomoConLaListaInterna = analizarIngreso(expresionDeLaListaInterna, true,false);
								esDefun = true;
							}
							
							
							if (operacionDeLaLista.compareToIgnoreCase("cond")==0){
								esCOND = true;
								atomoConLaListaInterna = analizarIngreso(expresionDeLaListaInterna, true,true);
							}
						}
					
					}
					
					if ((!esDefun) && (!esCOND))
						atomoConLaListaInterna = analizarIngreso(expresionDeLaListaInterna, defineList, reservada);
					
				}
				
				atomoDeRespuesta.lista.Agregar(atomoConLaListaInterna);
				String expresionDespuesDeLaListaInterna = expresionAParsear.substring(hastaDondeCortar + 1);
				expresionAParsear = expresionDespuesDeLaListaInterna;
				
				if (!esDefun){
					
					separador = new StringTokenizer(expresionDespuesDeLaListaInterna);
				} else {
					
					String nombreDeLaFuncion = atomoDeRespuesta.lista.getAtom(1).toString();
					this.funcionesDelUsuario.put(nombreDeLaFuncion,new Atomo());
					
					Atomo atomoConLaOperacion = analizarIngreso(expresionAParsear.trim(), false,false);
					atomoDeRespuesta.lista.Agregar(atomoConLaOperacion);
					separador = new StringTokenizer("");
					
					this.funcionesDelUsuario.remove(nombreDeLaFuncion);
				}
			} else{
				
				int desdeDondeCortar = expresionAParsear.indexOf(atomoActual.toString());
				expresionAParsear = expresionAParsear.substring(desdeDondeCortar);
				
				if (atomoActual.comienzaCon("'"))
					
					atomoActual = new Atomo(atomoActual.toString().substring(1));
					
				atomoDeRespuesta.lista.Agregar(atomoActual);
			}
		}
		
		return atomoDeRespuesta;
	}
	
	

	
	public boolean parentesisExactos(String expresion) {
			int parentesisAbiertos = 0;
			int parentesisCerrados = 0;
			
			for (int i=0 ; i < expresion.length() ; i++){
				if (expresion.charAt(i) == '(')
					parentesisAbiertos++;
				else if (expresion.charAt(i) == ')')
					parentesisCerrados++;
			}
			
			return parentesisAbiertos == parentesisCerrados;
		}
 
	
	public Atomo evaluar(Atomo atomoAEvaluar){
		Atomo AtomoDeRespuesta = new Atomo();
		
		if (atomoAEvaluar.esNulo)
			return new Atomo();
		
		if (atomoAEvaluar.EsLista()){
			
			Lista listaAEvaluar = atomoAEvaluar.lista;
			
			if (listaAEvaluar.esOperacion){
				
				String operacionDeLaLista = listaAEvaluar.getOp().toString(); 
				if ((operacionDeLaLista.compareToIgnoreCase("defun")!=0) && (operacionDeLaLista.compareToIgnoreCase("cond")!=0)) 
					for (int i=0 ; i < listaAEvaluar.size() ; i++){
						if (listaAEvaluar.getAtom(i).EsListaConOperacion()){
							Atomo listaEvaluada = this.evaluar(listaAEvaluar.getAtom(i));
							listaAEvaluar.remplaza(i, listaEvaluada);
						} else if (this.variablesDelUsuario.containsKey(listaAEvaluar.getAtom(i).toString())){
							Atomo valorDelAtomo = this.variablesDelUsuario.get(listaAEvaluar.getAtom(i).toString());						
							
							if (listaAEvaluar.esOperacion){
								if (!((i==1) && (listaAEvaluar.getOp().toString().compareTo("setq")==0)))
									listaAEvaluar.remplaza(i, valorDelAtomo);
							} else 
								listaAEvaluar.remplaza(i, valorDelAtomo);	
						}
					}								
			} else {
				return new Atomo(listaAEvaluar);
			}
			
						
			String operacion = listaAEvaluar.getOp().toString();
			if (predicadosList.existencia(new Atomo(operacion))){
				return evaluarPredicado(listaAEvaluar);
			} else if (operacion.compareToIgnoreCase("cdr")==0){
				return cdr(listaAEvaluar);
			} else if (operacion.compareToIgnoreCase("car")==0){
				return car(listaAEvaluar);			
			} else if (operacion.compareToIgnoreCase("cons")==0){
				return cons(listaAEvaluar);
			} else if (operacion.compareToIgnoreCase("+")==0){
				return sumar(listaAEvaluar);
			} else if (operacion.compareToIgnoreCase("*")==0){
				return multiplicar(listaAEvaluar);
			} else if (operacion.compareToIgnoreCase("-")==0){
				return restar(listaAEvaluar);
			} else if (operacion.compareToIgnoreCase("/")==0){
				return dividir(listaAEvaluar);
			} else if (operacion.compareToIgnoreCase("defun")==0){
				return defun(listaAEvaluar);
			} else if (this.funcionesDelUsuario.containsKey(operacion)){
				return operarFuncionDelUsuario(listaAEvaluar);
			} else if (operacion.compareToIgnoreCase("equal")==0){
                                return new Atomo(listaAEvaluar.getAtom(1).toString().compareTo(listaAEvaluar.getAtom(2).toString())==0);
			
			} else if (operacion.compareToIgnoreCase("cond")==0){
				return cond(listaAEvaluar);}
			
		} else{
			
			if (this.variablesDelUsuario.containsKey(atomoAEvaluar.toString()))
				AtomoDeRespuesta = this.variablesDelUsuario.get(atomoAEvaluar.toString());
			else
				
				AtomoDeRespuesta = atomoAEvaluar;	
		}
		
		return AtomoDeRespuesta;
	}

	

	private Atomo evaluarPredicado(Lista listaAEvaluar) {
		Atomo atomoDeRespuesta = new Atomo();
		
		String nextPredicado = listaAEvaluar.getAtom(0).toString();
		if (!predicadosList.existencia(new Atomo(nextPredicado)))
                        System.out.println("El predicado a evaluar no es correcot.");
		if (nextPredicado.compareTo("=")==0){
			if (!(listaAEvaluar.size() > 1))
                                System.out.println("El predicado no contiene operandos");
			boolean sonIguales = true;
			for (int i = 1 ; i < listaAEvaluar.size()-1 ; i++){
				sonIguales = listaAEvaluar.getAtom(i).equals(listaAEvaluar.getAtom(i+1));
				
				if (!sonIguales)
					atomoDeRespuesta = new Atomo(sonIguales);
			}

                        atomoDeRespuesta = new Atomo(sonIguales);
		} else if (nextPredicado.compareTo("/=")==0){
			if (!(listaAEvaluar.size() > 1))
                                System.out.println("El predicado no contiene operandos.");
			boolean sonDiferentes = true;
			
			for (int i = 1 ; i < listaAEvaluar.size()-1 ; i++){
				sonDiferentes = !listaAEvaluar.getAtom(i).equals(listaAEvaluar.getAtom(i+1));
				
				if (!sonDiferentes)
                                        atomoDeRespuesta = new Atomo(false);
			}
			return new Atomo(sonDiferentes);
		} else if (nextPredicado.compareTo("<")==0){
			if (!(listaAEvaluar.size() > 1))
                                System.out.println("El predicado no contiene operandos.");
			boolean esMenorQue = true;
			
			for (int i = 1; i <listaAEvaluar.size()-1 ; i++){
				
				if (!(listaAEvaluar.getAtom(i).esNumero()))
                                        System.out.println("El operando no es un numero");
				esMenorQue = listaAEvaluar.getAtom(i).getNumero() < listaAEvaluar.getAtom(i+1).getNumero();
				
				if (!esMenorQue)
                                        atomoDeRespuesta = new Atomo(false);
			}
			
                        atomoDeRespuesta = new Atomo(esMenorQue);
		} else if (nextPredicado.compareTo("<=")==0){
			if (!(listaAEvaluar.size() > 1))
                                System.out.println("El predicado no contiene operandos.");
			boolean esMenorIgualQue = true;
			
			for (int i = 1; i <listaAEvaluar.size()-1 ; i++){
				if (!(listaAEvaluar.getAtom(i).esNumero()))
                                        System.out.println("El operando no es un numero");
				esMenorIgualQue = listaAEvaluar.getAtom(i).getNumero() <= listaAEvaluar.getAtom(i+1).getNumero();
				if (!esMenorIgualQue)
                                        atomoDeRespuesta = new Atomo(false);
			}
			return new Atomo(esMenorIgualQue);
		} else if (nextPredicado.compareTo(">")==0){
			if (!(listaAEvaluar.size() > 1))
                                System.out.println("El predicado no contiene operandos.");
			boolean esMayorQue = true;
			
			for (int i = 1; i <listaAEvaluar.size()-1 ; i++){
				
				if (!(listaAEvaluar.getAtom(i).esNumero()))
                                        System.out.println("El predicado no contiene operandos.");
				esMayorQue = listaAEvaluar.getAtom(i).getNumero() > listaAEvaluar.getAtom(i+1).getNumero();
				
				if (!esMayorQue)
                                        atomoDeRespuesta = new Atomo(false);
			}
			
			return new Atomo(esMayorQue);
		} else if (nextPredicado.compareTo(">=")==0){
			if (!(listaAEvaluar.size() > 1))
                                System.out.println("El predicado no contiene operandos.");
			boolean esMayorIgualQue = true;
			
			for (int i = 1; i <listaAEvaluar.size()-1 ; i++){
				if (!(listaAEvaluar.getAtom(i).esNumero()))
                                        System.out.println("El predicado no contiene operandos.");
				esMayorIgualQue = listaAEvaluar.getAtom(i).getNumero() >= listaAEvaluar.getAtom(i+1).getNumero();
				if (!esMayorIgualQue)
                                        atomoDeRespuesta = new Atomo(false);
			}
                        atomoDeRespuesta = new Atomo(esMayorIgualQue);
		} 
                return atomoDeRespuesta;
	}

	

	
	private Atomo cond(Lista listaAEvaluar)  {
		if (listaAEvaluar.size()<2)
                        System.out.println("No se ha recibido ningun parametro.");
		
		
		int revisandoSubListaIndex = 1;
		boolean haEncontradoRespuesta = false;
		Atomo atomoDeRespuesta = new Atomo();
		
		while ((revisandoSubListaIndex < listaAEvaluar.size()) && (!haEncontradoRespuesta)){
			
			if (!listaAEvaluar.getAtom(revisandoSubListaIndex).EsLista()) 
                                System.out.println("No se ha ingresado una lista.");
                        else {
				
				
			}
			
			Lista evaluandoSubLista = listaAEvaluar.getAtom(revisandoSubListaIndex).lista;
			
			
			Atomo primerAtomo = evaluandoSubLista.getAtom(0);
			
			
			if (!((atomoDeRespuesta.esNulo) && (revisandoSubListaIndex==listaAEvaluar.size()-1))) {
				if ((!primerAtomo.EsLista()) && (!this.variablesDelUsuario.containsKey(primerAtomo.toString())))
                                        System.out.println("No esta definido por el usuario.");
                            }
			
			Atomo primerAtomoEvaluado = this.evaluar(primerAtomo);
			
			
			
			if (!primerAtomoEvaluado.esNulo){
				haEncontradoRespuesta = true;
					
				if (evaluandoSubLista.size() > 1)
					
					atomoDeRespuesta = this.evaluar(evaluandoSubLista.getAtom(evaluandoSubLista.size()-1));
				else
					
					atomoDeRespuesta = primerAtomoEvaluado; 
			} 
			
			revisandoSubListaIndex ++;
		}
		
		
		return atomoDeRespuesta;
	}

	


	
	private Atomo operarFuncionDelUsuario(Lista listaAEvaluar)  {
		
		int numeroDeParametrosQueIngreso = listaAEvaluar.size()-1;
		
		Lista listaDeLosParametros = this.funcionesDelUsuario.get(listaAEvaluar.getOp().toString()).lista.getAtom(0).lista;
		
		int numeroDeParametrosDeLaFuncion = listaDeLosParametros.size();	
		
		if (numeroDeParametrosDeLaFuncion!=numeroDeParametrosQueIngreso)
                        System.out.println("Cantidad de parametros incorrectos.");
		Hashtable<String,Atomo> mapaDeParametrosYValores = new Hashtable<String,Atomo>();
		
		for (int i =1 ; i <= numeroDeParametrosQueIngreso ; i++){
			mapaDeParametrosYValores.put(listaDeLosParametros.getAtom(i-1).toString(), listaAEvaluar.getAtom(i));
		}
		
		
		Atomo atomoDeLaOperacion = this.funcionesDelUsuario.get(listaAEvaluar.getOp().toString()).lista.getAtom(1);
		
		if (atomoDeLaOperacion.EsLista()){
			Atomo listaAEvaluarConParametrosMapeados = this.mapearParametrosEn(mapaDeParametrosYValores, new Atomo(atomoDeLaOperacion.lista)); 
			return this.evaluar(listaAEvaluarConParametrosMapeados);
		} else
			return atomoDeLaOperacion;
		
	}

	
	 
	private Atomo mapearParametrosEn(Hashtable<String, Atomo> mapaDeParametrosYValores, Atomo atomoEnDondeMapear) {
		
				
		Lista listaAEvaluar = new Lista(atomoEnDondeMapear.lista);
		listaAEvaluar.esOperacion = atomoEnDondeMapear.lista.esOperacion;
		
		
		for (int i= 0 ; i < listaAEvaluar.size(); i++){
			Atomo atomoActual = listaAEvaluar.getAtom(i);
			
			if (atomoActual.EsLista()){
				listaAEvaluar.remplaza(i,this.mapearParametrosEn(mapaDeParametrosYValores, atomoActual));
			} else{
				if (mapaDeParametrosYValores.containsKey(atomoActual.toString()))
					listaAEvaluar.remplaza(i,mapaDeParametrosYValores.get(atomoActual.toString()));
			}
		}
		
		return new Atomo(listaAEvaluar);
	}

	private Atomo defun(Lista listaAEvaluar)  {
		
		if (listaAEvaluar.size()!=4)
                        System.out.println("Para definir funcion se necesitan el nombre, parametros y su operacion");

                else{
			if (listaAEvaluar.getAtom(1).EsLista())
                                System.out.println("Para definir funcion se necesitan el nombre, parametros y su operacion");
			if (!listaAEvaluar.getAtom(2).EsLista())
                                System.out.println("Para definir funcion se necesitan el nombre, parametros y su operacion");
			
		}
		String nombreDeLaFuncion = listaAEvaluar.getAtom(1).toString();
		if (!esNombreDeFuncionValida(nombreDeLaFuncion))
                        System.out.println("No tiene nombre valido");
		
		Atomo atomoDeLaFuncion = new Atomo(new Lista(listaAEvaluar.subList(2, 4)));
		this.funcionesDelUsuario.put(nombreDeLaFuncion, new Atomo(new Lista(listaAEvaluar.subList(2, 4))));
		
		return new Atomo(nombreDeLaFuncion);
	}

	
	private boolean esNombreDeFuncionValida(String nombreDeLaFuncion)  {
		
		
		if (opList.existencia(new Atomo(nombreDeLaFuncion)))
                        System.out.println("Ese nombre ya esta implementado");
		
		String primerCaracter = Character.toString(nombreDeLaFuncion.charAt(0)); 
		try {
			int posibleNumero = Integer.parseInt(primerCaracter);
			return false;
		} catch(NumberFormatException noEmpiezaConNumero){
			return true;
		}
	}

	
	private Atomo dividir(Lista listaAEvaluar)  {
		float division=0;
		if (listaAEvaluar.getAtom(1).esNumero())
			division = listaAEvaluar.getAtom(1).getNumero();
		else
                        System.out.println("Solo se aceptan numeros");
		for (int i=2; i < listaAEvaluar.size() ; i++){
			if (listaAEvaluar.getAtom(i).esNumero()){
			
				division /= listaAEvaluar.getAtom(i).getNumero();
			} else
                                System.out.println("Solo se aceptan numeros");
                            }

		return new Atomo(division);
	}
	
	
	private Atomo restar(Lista listaAEvaluar)  {
		float resta=0;
		if (listaAEvaluar.getAtom(1).esNumero())
			resta = listaAEvaluar.getAtom(1).getNumero();
		else
			
                        System.out.println("Solo se aceptan numeros");
		boolean todosSonEnteros = true;
		
		for (int i=2; i < listaAEvaluar.size() ; i++){
			if (listaAEvaluar.getAtom(i).esNumero()){
				if (!listaAEvaluar.getAtom(i).esEntero())
					todosSonEnteros = false;
				
				resta -= listaAEvaluar.getAtom(i).getNumero();
			} else
				
                                 System.out.println("Solo se aceptan numeros");
                            }
		
		if (todosSonEnteros) 
			return new Atomo((int) resta);
		else 
			return new Atomo(resta);
	}

	
	private Atomo sumar(Lista listaAEvaluar)  {
		float suma = 0;
		boolean todosSonEnteros = true;
		
		for (int i=1; i < listaAEvaluar.size() ; i++){
			if (listaAEvaluar.getAtom(i).esNumero()){
				if (!listaAEvaluar.getAtom(i).esEntero())
					todosSonEnteros = false;
				
				suma += listaAEvaluar.getAtom(i).getNumero();
			} else
                                System.out.println("Solo se aceptan numeros");
		}
		
		if (todosSonEnteros) 
			return new Atomo((int) suma);
		else 
			return new Atomo(suma);
	}
	
	private Atomo multiplicar(Lista listaAEvaluar)  {
		float Multiplicacion = 1;
		boolean todosSonEnteros = true;
		
		for (int i=1; i < listaAEvaluar.size() ; i++){
			if (listaAEvaluar.getAtom(i).esNumero()){
				if (!listaAEvaluar.getAtom(i).esEntero())
					todosSonEnteros = false;
			
				Multiplicacion *= listaAEvaluar.getAtom(i).getNumero();
			} else
                                System.out.println("Solo se aceptan numeros");
		}
		
		if (todosSonEnteros)
			return new Atomo((int) Multiplicacion);
		else
			return new Atomo(Multiplicacion);
	}

	
	public Atomo cons(Lista listaAEvaluar)  {
		if (listaAEvaluar.size() != 3)
			
                        System.out.println("Se necesitan de dos parametros");
		Lista listaConstruida = new Lista();
		listaConstruida.Agregar(listaAEvaluar.getAtom(1));
		
		
		if (listaAEvaluar.getAtom(2).EsLista()){
			for (int i = 0; i < listaAEvaluar.getAtom(2).lista.size(); i++){
				if (!listaAEvaluar.getAtom(2).lista.getAtom(i).esNulo)
					listaConstruida.Agregar(listaAEvaluar.getAtom(2).lista.getAtom(i));
			}
		} else
			listaConstruida.Agregar(listaAEvaluar.getAtom(2));
		
		return new Atomo(listaConstruida);
	}

	
	public Atomo car(Lista listaAEvaluar)  {
		if (!this.operandoEsLista(listaAEvaluar))
                        System.out.println("La funcion CAR solo acepta una lista");
		Lista listaOperanda = this.evaluar(listaAEvaluar.getAtom(1)).lista;
		
		if (listaOperanda.empty())
			return new Atomo();
		
		Atomo primerAtomo = listaOperanda.getAtom(0);
		
		if (primerAtomo.EsListaConOperacion())
			primerAtomo = this.evaluar(primerAtomo);
		
		return primerAtomo;
	}

	
	public Atomo cdr(Lista listaAEvaluar) {
		
		if (!this.operandoEsLista(listaAEvaluar))
                        System.out.println("La funcion CDR solo acepta un operando");
		Lista listaOperanda = this.evaluar(listaAEvaluar.getAtom(1)).lista;
		
		if (listaOperanda.size()<2)
			return new Atomo();
		
		Lista subLista = new Lista(listaOperanda.subList(1, listaOperanda.size()));
		
		return new Atomo(subLista);
	}

	
	public boolean operandoEsLista(Lista listaAEvaluar)  {
		if (!listaAEvaluar.esOperacion)
                        System.out.println("Hubo un error. Intente de nuevo");
		
		if (listaAEvaluar.size()>2)
			return false;

		
		if (this.variablesDelUsuario.containsKey(listaAEvaluar.getAtom(1).toString()))
			return true;
			
		if (!listaAEvaluar.getAtom(1).EsLista())
			return false;
		
		return listaAEvaluar.esOperacion;
	}
	
	
	
	public int obtenerIndiceDelParentesisQueCierraAlPrimeroEn(String expresion) /*throws ExcepcionAl_MalInterpretacionDeGtLisp, ExcepcionAl_ExpresionMalBalanceada*/{
		expresion = expresion.trim();
		
		if (!((new Atomo(expresion).comienzaCon("'("))  ||  (new Atomo(expresion).comienzaCon("("))))
                        System.out.println("Hubo un error en la expresion. Revise de nuevo");

		int indice = expresion.indexOf('(')+1;
		int numeroDeParentesisAbiertosPorCerrar = 1;
		
		while (indice < expresion.length()){
			if (expresion.charAt(indice)=='('){
				numeroDeParentesisAbiertosPorCerrar++;
			} else if (expresion.charAt(indice)==')'){
				numeroDeParentesisAbiertosPorCerrar--;
				if (numeroDeParentesisAbiertosPorCerrar==0)
					return indice;
			}
			indice ++;
		}
                return indice;
	}
}
